<?php
/**
 * Created by PhpStorm.
 * User: yuanxr
 * Date: 2018/6/10
 * Time: 上午8:33
 */

namespace Utility\Extend;
/**
 * 对原生Array函数的扩展
 */
class EArray
{
    /**
     * 查找源数组中是否包含一个或多个键
     *
     * @param array $src 需要查找的源数组
     * @param string|int|array $target 需要查找的key值，可以为字符串、整数、数组
     * @return bool 所有的key全部被包含，返回true，否则返回false
     */
    public function hasKey(array $src, $target): bool
    {

        // target为非数组的处理
        if (!is_array($target)) {
            return array_key_exists($target, $src);
        }

        // target为数组的处理
        foreach ($target as $v) {
            if (!array_key_exists($v, $src)) {
                return false;
            }
        }

        // 所需要的key全部被包含，返回true
        return true;
    }

    /**
     * 查找源数组中是否包含一个或多个值
     *
     * @param array $src 需要查找的源数组
     * @param string|int|array $target 需要查找的value值，可以为字符串、整数、数组
     * @param boolean $strict 是否启用严格验证模式（即使用恒等操作），默认false
     * @return bool 所有的key全部被包含，返回true，否则返回false
     */
    public function hasValue(array $src, $target, bool $strict = false): bool
    {

        // target为非数组的处理
        if (!is_array($target)) {
            return in_array($target, $src, $strict);
        }

        // target为数组的处理
        foreach ($target as $v) {
            if (!in_array($v, $src, $strict)) {
                return false;
            }
        }

        // 所需要的value全部被包含，返回true
        return true;
    }

    /**
     * 返回源数组的维度
     *
     * @param mixed $src 需要获取维度的源数组
     * @return int 返回一个数组的维度
     */
    public function depth($src): int
    {
        if (!is_array($src)) {
            return 0;
        }
        $depth = 1;
        foreach ($src as $v) {
            if (is_array($v)) {
                $depth = max($depth, $this->depth($v) + 1);
            }
        }
        return $depth;
    }

    /**
     * 返回源数组中所有的键
     *
     * @param array $src 需要返回所有key的源数组
     * @return array 将源数组的所有key组合成数组返回
     */
    public function keys(array $src): array
    {
        return array_keys($src);
    }

    /**
     * 返回源数组中所有的值
     *
     * @param array $src 需要返回所有value的源数组
     * @return array 将源数组的所有value组合成数组返回
     */
    public function values(array $src): array
    {
        return array_values($src);
    }

    /**
     * 对源数组去重，并返回新数组
     *
     * @param array $src 需要去重的源数组
     * @return array 去除掉重复值的数组
     */
    public function unique(array $src): array
    {
        return array_unique($src);
    }

    /**
     * 取源数组长度
     *
     * @param array $src 需要统计的数组
     * @return int 数组的长度
     */
    public function len(array $src): int
    {
        return count($src);
    }

    /**
     * 从源数组中随机抽取若干个键值
     *
     * @param array $src 源数组
     * @param integer $size 需要随机取出的数组元素数量，默认1
     * @return array 从数组中取出一个或多个随机的单元，并返回随机条目的一个或多个键。
     *
     * 注意：
     * 此方法与php自带的array_rand不同，其size=1时，只返回key。当前方法却将key和value全部返回（即一维且一个元素的数组）
     */
    public function rand(array $src, int $size = 1)
    {
        $result = array_rand($src, $size);
        return $size == 1 ? $src[$result] : $result;
    }

    /**
     * 将源数组切分为多个数组
     *
     * @param array $src 需要切分的源数组
     * @param integer $size 切分时每个子数组的大小
     * @param boolean $preserve_keys 是否保留原来的键名(key)，默认false
     * @return array 按照要求切分的二维数组
     */
    public function chunk(array $src, int $size, bool $preserve_keys = false)
    {
        return array_chunk($src, $size, $preserve_keys);
    }

    /**
     * 过滤一个源数组
     *
     * @param array $src 遍历运行callback函数的源数组
     * @param callable $callback 过滤时使用的函数。如果本回调函数返回true，则保留该条目；如果本回调函数返回false，则删除该条目。
     * @return array 被过滤后的数组
     *
     * 示例：
     * arr::filter($array_src, function($value, $key) {
     *   return $key == 'name' || $value == 'hello'
     * })
     */
    public function filter(array $src, callable $callback)
    {
        return array_filter($src, $callback, ARRAY_FILTER_USE_BOTH);
    }

    /**
     * 对源数组进行Map运算
     *
     * @param array $src 遍历运行callback函数的源数组
     * @param callable $callback 回调函数，应用到每个数组里的每个元素
     * @return array 为数组的每个元素应用回调函数，并返回结果数组
     *
     * 示例：
     * arr::map($array_src, function($value) {
     * 	 return $value * 2;
     * })
     */
    public function map(array $src, callable $callback)
    {
        return array_map($callback, $src);
    }

    /**
     * reduce
     *
     * @param array $src 遍历运行callback函数的源数组
     * @param callable $callback 回调函数，应用到每个数组里的每个元素
     * @param mixed $initial 如果指定了可选参数 initial，该参数将在处理开始前使用，或者当处理结束，数组为空时的最后一个结果。默认null
     * @return mixed 为数组的每个元素应用回调函数，并返回结果数组
     *
     * 累加示例（注意initial参数的设置）：
     * arr::reduce($array_src, function($carry, $item) {
     * 	 return $carry += $item;
     * });
     *
     * 累乘示例（注意initial参数的设置）：
     * arr::reduce($array_src, function($carry, $item) {
     * 	 return $carry *= $item;
     * }, 1);
     *
     * 注意：
     * 当回调函数是计算乘法等操作时，如果没有initial的参与，第一个carry值为0或""，可能会导致结果的不确定性
     * 在使用该方法时，一定要灵活使用initial参数
     */
    public function reduce(array $src, callable $callback, $initial = null)
    {
        return array_reduce($src, $callback, $initial);
    }

    /**
     * 合并两个数组，并返回新数组
     *
     * @param array $src 需要合并的源数组
     * @param array $target 需要合并的目标数组
     * @return array 合并后的数组
     */
    public function merge(array $src, array $target)
    {
        return array_merge($src, $target);
    }


    /**
     * diff
     *
     * @param array $src 需要获得差集的源数组
     * @param array $targets 需要获得差集的目标数组（可以传入多个数组参数）
     * @return array 使用“值”比较的，差集结果数组
     */
    public function diff(array $src, array ...$targets)
    {
        return array_diff($src, ...$targets);
    }

    /**
     * diff_key
     *
     * @param array $src 需要获得差集的源数组
     * @param array $targets 需要获得差集的目标数组（可以传入多个数组参数）
     * @return array 使用“键”比较的，差集结果数组
     */
    public function diffKey(array $src, array ...$targets)
    {
        return array_diff_key($src, ...$targets);
    }

    /**
     * intersect
     *
     * @param array $src 需要获得交集的源数组
     * @param array $targets 需要获得交集的目标数组（可以传入多个数组参数）
     * @return array 使用“值”比较的，交集结果数组
     */
    public function intersect(array $src, array ...$targets)
    {
        return array_intersect($src, ...$targets);
    }

    /**
     * intersect_key
     *
     * @param array $src 需要获得交集的源数组
     * @param array $targets 需要获得交集的目标数组（可以传入多个数组参数）
     * @return array 使用“键”比较的，交集结果数组
     */
    public function intersectKey(array $src, array ...$targets)
    {
        return array_intersect_key($src, ...$targets);
    }

    /**
     * sort
     *
     * @param array $src 需要排序的源数组（特别注意：此处是引用传递，不返回结果，但改变源数据的值）
     * @return void 将源按“值”进行“正向”排序，并清除源数组的key
     *
     * 注意：
     * 此种排序后，会丢失key
     */
    public function sort(array &$src)
    {
        sort($src);
    }

    /**
     * rsort
     *
     * @param array $src 需要排序的源数组（特别注意：此处是引用传递，不返回结果，但改变源数据的值）
     * @return void 将源按“值”进行“反向”排序，并清除源数组的key
     *
     * 注意：
     * 此种排序后，会丢失key
     */
    public function rsort(array &$src)
    {
        rsort($src);
    }

    /**
     * ksort
     *
     * @param array $src 需要排序的源数组（特别注意：此处是引用传递，不返回结果，但改变源数据的值）
     * @return void 将源按“键名”进行“正向”排序
     */
    public function ksort(array &$src)
    {
        ksort($src);
    }

    /**
     * krsort
     *
     * @param array $src 需要排序的源数组（特别注意：此处是引用传递，不返回结果，但改变源数据的值）
     * @return void 将源按“键名”进行“反向”排序
     */
    public function krsort(array &$src)
    {
        krsort($src);
    }

    /**
     * asort
     *
     * @param array $src 需要排序的源数组（特别注意：此处是引用传递，不返回结果，但改变源数据的值）
     * @return void 将源按“值”进行“正向”排序，并保留key信息
     */
    public function asort(array &$src)
    {
        asort($src);
    }

    /**
     * arsort
     *
     * @param array $src 需要排序的源数组（特别注意：此处是引用传递，不返回结果，但改变源数据的值）
     * @return void 将源按“值”进行“反向”排序，并保留key信息
     */
    public function arsort(array &$src)
    {
        arsort($src);
    }

}
